package com.moons.idevices.printers;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.text.TextUtils;
import android.util.Log;

import com.csnprintersdk.csnio.CSNPOS;
import com.csnprintersdk.csnio.CSNUSBPrinting;
import com.csnprintersdk.csnio.csnbase.CSNIOCallBack;
import com.moons.idevices.Common;
import com.moons.idevices.IPrinter;
import com.moons.idevices.R;
import com.moons.idevices.model.Appointment;
import com.moons.idevices.model.Visitor;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;


/**
 * 2 寸打印机（58mm 打印机）最大宽度不超过 384 点 3 寸打印机（80mm 打印机）最大宽度不超过 576 点
 */
public class EP261CK extends BasePrinter implements Printer, CSNIOCallBack {
    private final String TAG = this.getClass().getSimpleName();

    private UsbManager mUsbManager;
    private UsbDevice mDevice;
    CSNPOS mPos = new CSNPOS();
    CSNUSBPrinting mUsb = new CSNUSBPrinting();
    PendingIntent pendingIntent;

    private Disposable reconnectDisposable;

    private int lanCode = LAN_CODE_GBK;


    public EP261CK(IPrinter iPrinter, Context context, UsbDevice device) {
        mIPrinter = iPrinter;
        mContext = context;
        mDevice = device;
        mPos.Set(mUsb);
        mUsb.SetCallBack(this);
        regBroadcastReceiver();
        Intent intent = new Intent(Common.ACTION_USB_DEVICE_PERMISSION_GRANTED);
        intent.putExtra(Common.VENDOR_ID, device.getVendorId());
        intent.putExtra(Common.PRODUCT_ID, device.getProductId());


        pendingIntent = PendingIntent.getBroadcast(mContext, 1, intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);

        mUsbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);


    }


    @Override
    public void connect() {
        Log.d(TAG, "connect mUsb.IsOpened(): " + mUsb.IsOpened());

        if (mUsb.IsOpened()) {

            mIPrinter.onConnected(isPrintFunctional());
        } else {

            if (!mUsbManager.hasPermission(mDevice)) {

//                Toast.makeText(mContext, "请授予USB设备权限", Toast.LENGTH_SHORT).show();
                ShowToast("请授予USB设备权限");

                mUsbManager.requestPermission(mDevice, pendingIntent);

            } else {
                mUsb.Open(mUsbManager, mDevice, mContext);
            }

        }


    }

    private void reConnect() {

    }

    @Override
    public void disconnect() {
        Log.i(TAG, "disconnect: ");
        unRegBroadcastReceiver();
        mUsb.Close();
        if (reconnectDisposable != null && !reconnectDisposable.isDisposed()) {
            reconnectDisposable.dispose();
        }
    }

    @Override
    public boolean isPrintFunctional() {
        byte[] status = new byte[1];
        if (mUsb.IsOpened()) {
            if (mPos.POS_RTQueryStatus(status, STATUS_TYPE_PRINTER_ERROR, 1000, 2)) {

                if ((status[0] & 0x08) == 0x08) {
                    //判断切刀是否异常
                    ShowToast("切刀异常");
                    return false;
                }
                if ((status[0] & 0x40) == 0x40) {
                    //判断打印头是否在正常值范围内
                    ShowToast("打印头异常");
                    return false;
                }
                if (mPos.POS_RTQueryStatus(status, STATUS_TYPE_PRINTER_OFF_LINE, 1000, 2)) {

                    if ((status[0] & 0x04) == 0x04) {
                        //判断合盖是否正常
                        ShowToast("合盖异常");
                        return false;
                    }

                    if ((status[0] & 0x20) == 0x20) {

                        //判断是否缺纸
                        ShowToast("缺纸");
                        return false;
                    }

                } else {
                    ShowToast("打印机连接异常");
                }


                return true;
            } else {

                ShowToast("打印机连接异常");
            }
        }


        return false;
    }


    @Override
    public void printAppointment(Appointment appointment, boolean isCut) {
        Log.d(TAG, "printAppointment: ");

        if (!isPrintFunctional()) {
            connect();
            return;
        }


        printTitle(mContext.getString(R.string.appointment));


        if (!TextUtils.isEmpty(appointment.getTips())) {

            printContent(String.format(mContext.getString(R.string.text_tips), appointment.getTips()));

            //行高 (0,255]
        }

        if (!TextUtils.isEmpty(appointment.getName())) {

            printContent(String.format(mContext.getString(R.string.text_name), appointment.getName()));

        }

        if (!TextUtils.isEmpty(appointment.getShangHaiQRCode())) {

            printContent(String.format(mContext.getString(R.string.text_shanghai_qr_code), appointment.getShangHaiQRCode()));

        }

        if (!TextUtils.isEmpty(appointment.getTemperature())) {

            printContent(String.format(mContext.getString(R.string.text_tmperatur), appointment.getTemperature()));

        }

        if (!TextUtils.isEmpty(appointment.getDateAndTime())) {

            printContent(String.format(mContext.getString(R.string.text_date_time), appointment.getDateAndTime()));

        }

        if (appointment.isTempAuthorize()) {

            if (!TextUtils.isEmpty(appointment.getMatterOfVisit())) {

                printContent(String.format(mContext.getString(R.string.text_subject_matter_of_visit), appointment.getMatterOfVisit()));

            }

            if (!TextUtils.isEmpty(appointment.getTmpAuthorizer())) {

                printContent(String.format(mContext.getString(R.string.text_tmp_licensor), appointment.getTmpAuthorizer()));

            }

        } else {


            if (!TextUtils.isEmpty(appointment.getWorkOrder())) {

                printContent(String.format(mContext.getString(R.string.text_work_order), appointment.getWorkOrder()));

            }

            if (!TextUtils.isEmpty(appointment.getVisitorType())) {

                printContent(String.format(mContext.getString(R.string.text_visitor_type), appointment.getVisitorType()));

            }

        }

        if (!TextUtils.isEmpty(appointment.getQrcode())) {
            printContent(mContext.getString(R.string.text_qr_code));

            printQRCode(appointment.getQrcode());
            printBlankLine();
            printBlankLine();
        }


        mPos.POS_FeedLine();
        mPos.POS_FeedLine();


        if (isCut) {

            fullCut();
        }


    }

    @Override
    public void printVisitor(Visitor visitor, boolean isCut) {
        Log.d(TAG, "printVisitor: ");

        if (!isPrintFunctional()) {
            connect();
            return;
        }

        printTitle("访客信息");


        if (!TextUtils.isEmpty(visitor.getName())) {
            printContent("访客姓名：" + visitor.getName());
        }
        if (!TextUtils.isEmpty(visitor.getCellPhoneNumber())) {
            printContent("手机号码：" + visitor.getCellPhoneNumber());
        }
        if (!TextUtils.isEmpty(visitor.getIdCardNumber())) {
            printContent("证件号：  " + visitor.getIdCardNumber());
        }
        if (!TextUtils.isEmpty(visitor.getType())) {
            printContent("访客类型：" + visitor.getType());
        }

        if (!TextUtils.isEmpty(visitor.getHealthCode())) {
            printContent("随申码：  " + visitor.getHealthCode());
        }
        if (!TextUtils.isEmpty(visitor.getTemp())) {
            printContent("体温：    " + visitor.getTemp());
        }
        printBlankLine();

        if (isCut) {

            fullCut();

        }
    }

    private void fullCut() {
        mPos.POS_FullCutPaper();
    }

    @Override
    public void printQRCode(String qrcode, IPrinter iPrinter) {
        if (!isPrintFunctional()) {
            connect();
            return;
        }
        mPos.POS_S_Align(ALIGN_MIDDLE);

        iPrinter.actionResult(printQRCode(qrcode));
        printBlankLine();
        mPos.POS_FeedLine();
        mPos.POS_FeedLine();
        fullCut();
    }

    @Override
    public void printText(String text, IPrinter iPrinter) {
        if (!isPrintFunctional()) {
            connect();
            return;
        }

        iPrinter.actionResult(printContent(text));
        printBlankLine();
        mPos.POS_FeedLine();
        mPos.POS_FeedLine();
        fullCut();
    }


    @Override
    public void OnOpen() {
        Log.i(TAG, "OnOpen: ");
        if (reconnectDisposable != null && !reconnectDisposable.isDisposed()) {
            reconnectDisposable.isDisposed();
        }


        if (mIPrinter != null) {
            mIPrinter.onConnected(isPrintFunctional());
        }

    }

    @Override
    public void OnOpenFailed() {
        Log.i(TAG, "OnOpenFailed: ");
        if (mIPrinter != null) {
            mIPrinter.onConnected(false);
        }
    }

    /**
     * 调用mUsb.close()<p>
     * 关闭连接，会调用回调接口 OnClose，重复 Close 不会多次调用回调。
     * <p/>
     */
    @Override
    public void OnClose() {
        Log.i(TAG, "OnClose: ");

        reconnectDisposable = Observable.interval(5, TimeUnit.SECONDS)
                .observeOn(Schedulers.io())
                .subscribeOn(Schedulers.io())
                .subscribe(aLong -> {

                    Log.i(TAG, "OnClose: reconnect !");
                    connect();

                }, Throwable::printStackTrace);

    }


    private BroadcastReceiver usbDeviceReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {

            boolean granted = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false);
            Log.d(TAG, "onReceive permission granted: " + granted);
            if (!granted) {
                if (mIPrinter != null) {
                    mIPrinter.onConnected(false);
                }
                return;
            }


            if (intent.getAction().equals(Common.ACTION_USB_DEVICE_PERMISSION_GRANTED)) {

                int vendorID = intent.getIntExtra(Common.VENDOR_ID, -1);
                int productID = intent.getIntExtra(Common.PRODUCT_ID, -1);

                if (vendorID == -1 || productID == -1) {

                    return;
                }

                final UsbManager mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
                HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();

                for (UsbDevice device : deviceList.values()) {

                    if (device.getVendorId() == vendorID && device.getProductId() == productID) {

                        mUsb.Open(mUsbManager, device, mContext);
                        break;
                    }


                }


            }


        }
    };

    void regBroadcastReceiver() {

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Common.ACTION_USB_DEVICE_PERMISSION_GRANTED);

        mContext.registerReceiver(usbDeviceReceiver, intentFilter);

    }

    void unRegBroadcastReceiver() {

        if (mContext != null) {

            mContext.unregisterReceiver(usbDeviceReceiver);
        }


    }

    public void printBlankLine() {

        mPos.POS_TextOut("\r\n", LAN_CODE_GBK, ORG_X_ZERO, WIDTH_TIMES_ZERO, HEIGHT_TIMES_ZERO, FONT_TYPE, FONT_STYLE_NORMAL);

    }


    private void printTitle(String title) {

        mPos.POS_Reset();
        mPos.POS_S_Align(ALIGN_MIDDLE);
        mPos.POS_TextOut(title + "\r\n", LAN_CODE_GBK, ORG_X_ZERO, WIDTH_TIMES_X1, HEIGHT_TIMES_X1, FONT_TYPE, FONT_STYLE_BOLD);

        printDividerLine();

    }

    private boolean printContent(String content) {

        mPos.POS_S_Align(ALIGN_LEFT);
        mPos.POS_SetLineHeight(40);
        return mPos.POS_TextOut(content + "\r\n", LAN_CODE_GBK, ORG_X_ZERO, WIDTH_TIMES_ZERO, HEIGHT_TIMES_ZERO, FONT_TYPE, FONT_STYLE_NORMAL);

    }

    private boolean printQRCode(String code) {

        mPos.POS_S_Align(ALIGN_MIDDLE);
        return mPos.POS_S_SetQRcode(code, 8, 0, 2);

    }

    public static final int STATUS_TYPE_PRINTER = 1;
    public static final int STATUS_TYPE_PRINTER_OFF_LINE = 2;
    public static final int STATUS_TYPE_PRINTER_ERROR = 3;
    public static final int STATUS_TYPE_PRINTER_PAPER_SENSOR = 4;


    public static final int ALIGN_LEFT = 0;
    public static final int ALIGN_MIDDLE = 1;
    public static final int ALIGN_RIGHT = 2;

    //0-GBK 1-UTF8 3-BIG5 4-SHIFT-JIS 5-EUC-KR

    public static final int LAN_CODE_GBK = 0;
    public static final int LAN_CODE_UTF8 = 1;
    public static final int LAN_CODE_BIG5 = 3;
    public static final int LAN_CODE_SHIFT_JIS = 4;
    public static final int LAN_CODE_EUC_KR = 5;

    /**
     * Orgx指定 X 方向（水平）的起始点位置离左边界的点数。
     */
    public static final int ORG_X_DEFAULT = 16;
    public static final int ORG_X_ZERO = 0;

    public static final int WIDTH_TIMES_ZERO = 0;
    public static final int HEIGHT_TIMES_ZERO = 0;
    public static final int WIDTH_TIMES_X1 = 1;
    public static final int HEIGHT_TIMES_X1 = 1;

    /**
     * FontType 指定字符的字体类型。<p/>
     * (0x00 标准 ASCII 12x24)<p/>
     * (0x01 压缩 ASCII 9x17)
     */
    public static final int FONT_TYPE = 0;

    /**
     * 指定字符的字体风格。可以为以下列表中的一个或若干个。<p/>
     * (0x00 正常) <p/>
     * (0x08 加粗) <p/>
     * (0x80 1 点粗的下划线)<p/>
     * (0x100 2 点粗的下划线)<p/>
     * (0x200 倒置、只在行首有效)<p/>
     * (0x400 反显、黑底白字) <p/>
     * (0x1000 每个字符顺时针旋转 90 度)<p/>
     */
    public static final int FONT_STYLE_NORMAL = 0x00;
    public static final int FONT_STYLE_BOLD = 0x08;
    public static final int FONT_STYLE_ONE_BOLD_UNDERLINE = 0x80;
    public static final int FONT_STYLE_TWO_BOLD_UNDERLINE = 0x100;

    @Override
    public void printDividerLine() {

        mPos.POS_TextOut("--------------------------------\r\n", LAN_CODE_GBK, ORG_X_ZERO, WIDTH_TIMES_ZERO, HEIGHT_TIMES_ZERO, FONT_TYPE, FONT_STYLE_NORMAL);

    }
}
